#include "common.h"

void iterate_dictionary(GVariant *dictionary) {
    g_print("iterate_dictionary for dictionar 0x%0x\n", dictionary);
    if (dictionary == NULL) {
        g_print("invalid parameter NULL passed into iterate_dictionary\n");
        return;
    }
    GVariantIter iter;
    GVariant *value;
    gchar *key_value;
    gchar *key;
    gsize length;
    g_variant_iter_init(&iter, dictionary);
    while (g_variant_iter_next(&iter, "{sv}", &key, &value)) {
        const gchar *type = g_variant_get_type_string(value);
        g_print("\tItem '%s' has type '%s', with value", key, type);
        const gchar *property = "null";
        if (g_strcmp0(type, "s") == 0) {
            gsize length = 0;
            property = g_variant_get_string(value, &length);
            g_print(" '%s'\n", property);
        } else if (g_strcmp0(type, "b") == 0) {
            gboolean p = g_variant_get_boolean(value);
            property = p ? "1 (TRUE)" : "0 (FLASE)";
            g_print(" '%s'\n", property);
        } else if (g_strcmp0(type, "as") == 0) {
            gsize count = 0;
            const gchar **properties = g_variant_get_strv(value, &count);
            for (int i = 0; i < count; i++) {
                g_print("'%s', ", properties[i]);
            }
            g_print("\n");
        } else {
            g_print("add format for this type '%s'\n", type);
        }
        g_variant_unref(value);
        g_free(key);
    }
}

GDBusConnection *get_system_bus_connection() {
    GError *error = NULL;
    GDBusConnection *conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
    if (conn == NULL) {
        g_print("g_bus_get_sync error: %s\n", error->message);
    }
    return conn;
}

gboolean get_modem_paths(gchar **modem_paths, gsize *count) {
    g_type_init();
    GDBusConnection *conn = get_system_bus_connection();
    GError *error = NULL;
    GVariant *result = g_dbus_connection_call_sync(conn, OFONO_SERVICE_NAME, OBJECT_PATH, OFONO_MANAGER,
            "GetModems", NULL, G_VARIANT_TYPE("(a(oa{sv}))"), G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
    if (result == NULL) {
        g_print("g_dbus_connection_call_sync error: %s\n", error->message);
        return FALSE;
    }
    g_print("GetModems returns type %s, children count %d\n", g_variant_get_type(result), g_variant_n_children(result));
    g_print("GetModems returns is a container %d\n", g_variant_is_container(result));

    *count = 0;

    GVariantIter iter;
    GVariant *modems = g_variant_get_child_value(result, 0);
    GVariant *child;
    g_variant_iter_init(&iter, modems);
    while ((child = g_variant_iter_next_value(&iter))) {
        g_print("child type '%s', children count %d\n", g_variant_get_type_string(child), g_variant_n_children(child));
        g_print("child is container %d\n", g_variant_is_container(child));
        GVariant *object_path = g_variant_get_child_value(child, 0);
        //memset(modem_paths[*count], 0x0, MODEM_PATH_LIMIT);
        const gchar *path;
        g_variant_get(object_path, "o", &path);
        gsize len = strlen(path);
        modem_paths[*count] = path;
        g_print("path is '%s', len is %d, copied '%s'\n", path, len, modem_paths[*count]);
        (*count)++;

        GVariant *info = g_variant_get_child_value(child, 1);
        iterate_dictionary(info);
        g_variant_unref(child);
    }

    return TRUE;
}

void hexdump(const gchar *bytes, const gsize len, const gchar *msg) {
    g_print("%s:\n", msg);
    g_print("  addr\t\t\t\thex\t\t\t\tASCII\n");
    char addr_fmt[] = "0x%05x   ";
    char hex_fmt[] = "%02x ";
    char ascii_fmt[] = "%c";
    char non_print[] = "*";
    int rows = len / 16;
    for (int i = 0; i < rows; i++) {
        int col = i*16;
        g_print(addr_fmt,  col);
        for (int j = 0; j < 16; j++) {
            g_print(hex_fmt, bytes[j+col]);
        }
        g_print("  ");
        for (int j = 0; j < 16; j++) {
            if (isprint(bytes[j+col])) {
                g_print(ascii_fmt, bytes[j+col]);
            } else {
                g_print(non_print);
            }
        }
        g_print("\n");
    }
    // deal with the last line
    int col = rows * 16;
    if (col < len) {
        g_print(addr_fmt, col);
        for (int j = 0; j < 16; j++) {
            if (j+col < len) {
                g_print(hex_fmt, bytes[j+col]);
            } else {
                g_print("   ");
            }
        }
        g_print("  ");
        for (int j = col; j < len; j++) {
            if (isprint(bytes[j])) {
                g_print(ascii_fmt, bytes[j]);
            } else {
                g_print(non_print);
            }
        }
        g_print("\n");
    }
}
